package Client.proxy;

import Client.IOClient;
import Client.circuitBreaker.CircuitBreaker;
import Client.circuitBreaker.CircuitBreakerProvider;
import Client.retry.guavaRetry;
import Client.rpcClient.RpcClient;
import Client.rpcClient.impl.NettyRpcClient;
import Client.rpcClient.impl.SimpleSocketRpcClient;
import Client.serviceCenter.ServiceCenter;
import Client.serviceCenter.ZKServiceCenter;
import common.Message.RpcRequest;
import common.Message.RpcResponse;
import common.pojo.User;
import lombok.AllArgsConstructor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理: invoke：封装请求并返回响应
 */
@AllArgsConstructor
public class ClientProxy implements InvocationHandler {

    private String host;
    private int port;
    private RpcClient rpcClient;
    private ServiceCenter serviceCenter;
    private CircuitBreakerProvider circuitBreakerProvider;

    public ClientProxy() throws InterruptedException {
        serviceCenter = new ZKServiceCenter();
        rpcClient = new NettyRpcClient(serviceCenter);
        circuitBreakerProvider = new CircuitBreakerProvider();
    }

    // hard code：host、port、choose，默认使用Netty，已废弃
    public ClientProxy(String host, int port, int choose) {
        switch (choose) {
            case 0:
                rpcClient = new NettyRpcClient(host, port);
                break;
            case 1:
                rpcClient = new SimpleSocketRpcClient(host, port);
                break;
        }
    }

    public ClientProxy(String host, int port) {
        rpcClient = new NettyRpcClient(host, port);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理调用方法" + method.getName());
        // 构建RpcRequest请求(新增)
        RpcRequest request = RpcRequest.builder()
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .params(args)
                .paramTypes(method.getParameterTypes()).build();
        System.out.println("netty_rpcRequest = " + request);
        // 熔断器
        CircuitBreaker circuitBreaker = circuitBreakerProvider.getCircuitBreaker(method.getName());
        if (!circuitBreaker.allowRequest()){
            System.out.println("熔断器不允许请求");
            return null;
        }
        // 发送请求并得到RpcResponse响应
        // RpcResponse response = xxxClient.sendRequest(host, port, request);
        RpcResponse response;
        // 后续添加逻辑，为保持幂等性，只对白名单上的服务进行重试
        if (serviceCenter.checkRetry(request.getInterfaceName())) {
            // 调用retry框架进行重试
            response = new guavaRetry().sendServiceWithRetry(request, rpcClient);
            System.out.println("重试后 response = " + response);
        } else
            response = rpcClient.sendRequest(request);

        if (response != null) {
            // 判断data返回类型是否是User
            if (response.getData().getClass() == User.class) {
                System.out.println("返回类型是User");
            }
            return response.getData();
        } else
            return null;
    }

    // 动态生成实现接口的代理对象
    public <T> T getProxy(Class<T> clazz) {
        Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, this);
        return (T) o;
    }
}